/*!
 * # 模块 JS:
 *  Management - 日历管理
 * 
 * # 描述:
 *  向管理员提供一个日历的管理界面。管理人员可以指定工作日、节假日或者为日期定义节日名称。
 * 
 * Copyright (c), 上海沃恩信息科技有限公司.
 * All rights reserved.
 * Licensed under BSD (https://www.pittypat.work/bsd.html).
 */

/*
 * @param {Object} $    jQuery 命名空间。
 * @param {Object} $$   pittypat 命名空间。
 * @param {Object} _mod 模块 Apps (应用与功能) 的命名空间。
 * 
 * 使用 pittypat.namespace('...') 以确保 _mod 命名空间是存在的。
 * 
 * 更多说明请参见：
 * https://www.pittypat.work/com/waln/pittypat/coding/help/index.html#js。
 */
(function ($, $$, _mod) {
    'use strict';

    /*
     * 为登录用户注册一个处理函数。
     * 由于没有为匿名用户注册处理函数，那么当发现用户尚未登录时，则会默认跳转到首页（登录页）。
     * 
     * 如果需要为匿名用户添加处理逻辑，应该使用如下格式的代码：
     * $$({
     *     authorized: function (_) {
     *         ...
     *     },
     *     anonymous: function (_) {
     *         // 跳转到自定义的登录页面
     *         window.location = '../../../../login.html';
     *     }
     * });
     * 
     * 如果需要自定义登录页面，则可能还需要添加 init 等处理函数。详细帮助请参见：
     * https://www.pittypat.work/com/waln/pittypat/ref/help/pittypat.js.html#pittypat。
     *
     * 参数 _ 的定义如下：
     * {
     *    user:  {Object},  // (只读)当前用户的用户信息
     *    app:   {Object},  // (只读)当前应用的命名空间，如果无法定位，则为 null
     *    mod:   {Object},  // (只读)当前模块的命名空间，如果无法定位，则为 null
     *    init:  {Boolean}, // (只读)是否正在初始化页面
     *    first: {Boolean}, // (只读)是否首次执行 authorized
     *    data:  {any}      // (读写)前述的 data 数据，或 data 函数返回的结果
     * }
     */
    $$(function (_) {
        var
            // 模块 UI 命名空间
            _ui = _mod.ui = _mod.ui || {},
            // 模块 API 命名空间
            _api = _mod.api,
            // 日历表格
            $calendar = $('#calendar'),
            // 当前日期
            today = new Date(),
            // 当前日期的年份
            todayYear = today.getFullYear(),
            // 当前日期的月份
            todayMonth = today.getExactMonth(),
            // 当前日期的日期
            todayDay = today.getDate();

        if (_.init) {
            // 默认显示当前月份
            $calendar.data('year', today.getFullYear()).data('month', today.getExactMonth());

            // 创建第一行
            function createFirstLine(year, month, lines) {
                var line = [],
                    // 本月第一天对应的星期
                    week = new Date(year, month - 1, 1).getDay() || 7;

                if (week > 1) {
                    // 本月第一天不是周一
                    var
                        // 上一月隶属的年份
                        prevMonthYear = year - (month > 1 ? 0 : 1),
                        // 上一月
                        prevMonth = month > 1 ? month - 1 : 12,
                        // 上一月中的天数
                        prevMonthDays = $$.util.date.daysInMonth(prevMonthYear, prevMonth);

                    // 第一行上一个月中的日期
                    for (var i = week - 2; i >= 0; --i) {
                        line.push({
                            year: prevMonthYear,
                            month: prevMonth,
                            day: prevMonthDays - i,
                            type: 'prev-month'
                        });
                    }

                    // 第一行本月中的日期
                    for (var i = week; i < 8; ++i) {
                        line.push({
                            year: year,
                            month: month,
                            day: 1 + (i - week),
                            type: 'this-month'
                        });
                    }
                } else {
                    // 本月第一天是周一
                    for (var i = 0; i < 7; ++i) {
                        line.push({
                            year: year,
                            month: month,
                            day: 1 + i,
                            type: 'this-month'
                        });
                    }
                }

                lines.push(line);
            }

            // 创建中间行
            function createMiddleLines(year, month, lines, days, lastDays) {
                var
                    // 第一行最后一个日期
                    s = lines[0][6].day,
                    // 除去第一行和最后一行外，本月还剩下的天数
                    n = days - s - lastDays,
                    // 行数
                    ln = Math.floor(n / 7),
                    line = null, i = 0, j = 0;

                for (i = 0; i < ln; ++i) {
                    line = [];
                    for (j = 0; j < 7; j++) {
                        line[j] = {
                            year: year,
                            month: month,
                            day: s + 1 + i * 7 + j,
                            type: 'this-month'
                        };
                    }
                    lines.push(line);
                }
            }

            // 创建最后一行
            function createLastLine(year, month, lines, lastDays) {
                var
                    // 下一月隶属的年份
                    nextMonthYear = month == 12 ? year + 1 : year,
                    // 下一月
                    nextMonth = month == 12 ? 1 : month + 1,
                    // 最后一行
                    line = [],
                    // 已经添加的所有行中最后一天
                    lastDay = lines[lines.length - 1][6].day,
                    i = 1;

                // 本月中的日期
                for (; i <= lastDays; ++i) {
                    line.push({
                        year: year,
                        month: month,
                        day: lastDay + i,
                        type: 'this-month'
                    });
                }

                // 下一月中的日期
                for (var k = i; i <= 7; ++i) {
                    line.push({
                        year: nextMonthYear,
                        month: nextMonth,
                        day: i - k + 1,
                        type: 'next-month'
                    });
                }

                lines.push(line);
            }

            // 根据服务器返回的结果和当前查询参数创建当前选中月份中的所有行
            // 每一行代表一周
            function createLines(args) {
                var lines = [];

                // 第一行
                createFirstLine(args.year, args.month, lines);

                // 中间行
                var
                    // 本月总天数
                    days = $$.util.date.daysInMonth(args.year, args.month),
                    // 最后一行包含的本月的天数
                    lastDays = (days - lines[0][6].day) % 7;

                createMiddleLines(args.year, args.month, lines, days, lastDays);

                // 最后一行
                if (lastDays > 0) {
                    createLastLine(args.year, args.month, lines, lastDays);
                }

                return lines;
            }

            // 查找指定日期对应的服务器信息
            function findInfo(v, date) {
                if (v && v.length) {
                    for (var i = 0, info = null; i < v.length; ++i) {
                        info = v[i];
                        if (info.value.year == date.year &&
                            info.value.month == date.month &&
                            info.value.day == date.day) {
                            return info;
                        }
                    }
                }

                return null;
            }

            // 判断指定的日期是否工作日
            function isWorkday(d) {
                return (new Date(d.year, d.month - 1, d.day).getDay() || 7) < 6;
            }

            // 设置工作日和节假日
            function setup(lines, dates) {
                lines.each(function (line) {
                    line.each(function (d) {
                        var info = findInfo(dates, d);

                        if (info) {
                            d.isWorkday = info.isWorkday === true ? true : (info.isWorkday === false ? false : isWorkday(d));
                            d.festivals = info.festivals;
                        } else {
                            d.isWorkday = isWorkday(d);
                            d.festivals = '';
                        }

                        // 是否今天
                        d.isToday = d.year == todayYear && d.month == todayMonth && d.day == todayDay;
                    });
                });
            }

            // 显示一行
            function showLine(line, $line) {
                line.each(function (date) {
                    var $td = $(
                        '<td class="pt-model">' +
                        '<div class="day" data-target-dialog="#set-dialog">' +
                        '<span class="day-value"></span>' +
                        '<span class="day-name"></span>' +
                        '</div>' +
                        '</td>');

                    $td.find('.day-value').text(date.day);
                    $td.find('.day-name').text(date.festivals || (date.isToday ? '今天' : ''));
                    $td.children().addClass(date.type + '-day').toggleClass('holiday', !date.isWorkday).toggleClass('today', date.isToday);

                    $td.data('model', date);
                    $td.appendTo($line);
                });
            }

            // 显示所有行
            function showLines(lines) {
                var $lines = $calendar.children('tbody').empty();

                lines.each(function (line) {
                    var $line = $('<tr></tr>');
                    showLine(line, $line);
                    $line.appendTo($lines);
                });
            }

            _api.dates
                .on('args', function (e) {
                    e.args = {
                        year: $calendar.data('year'),
                        month: $calendar.data('month')
                    };
                    $$.ui.msg = '...';
                })
                .on('success', function (e) {
                    // 创建所有行
                    var lines = createLines(e.args);

                    // 设置工作日和节假日
                    setup(lines, e.result);

                    // 显示行
                    showLines(lines);

                    // 显示月份
                    $('#this-year').text(e.args.year);
                    $('#this-month').text(e.args.month.toString().padLeft('0', 2));
                    $$.ui.msg = '';
                });

            // 上一月
            $('#to-prev-month').on('click', function () {
                var year = $calendar.data('year'),
                    month = $calendar.data('month');

                if (month == 1) {
                    month = 12;
                    year = year - 1;
                } else {
                    --month;
                }

                $calendar.data('year', year).data('month', month);
                _api.dates();
            });

            // 当前月份
            $('#to-current-month').on('click', function () {
                var year = $calendar.data('year'),
                    month = $calendar.data('month');

                if (year == todayYear && month == todayMonth) {
                    return;
                }

                $calendar.data('year', todayYear).data('month', todayMonth);
                _api.dates();
            });

            // 下一月
            $('#to-next-month').on('click', function () {
                var year = $calendar.data('year'),
                    month = $calendar.data('month');

                if (month == 12) {
                    month = 1;
                    year = year + 1;
                } else {
                    ++month;
                }

                $calendar.data('year', year).data('month', month);
                _api.dates();
            });
            
            // 设置日期
            $('#set-dialog')
                .on('opening', function (e) {
                    $('#set-dialog-title').text($$.util.fmt.day(e.model));
                    $('#set-is-holiday').prop('checked', !e.model.isWorkday);
                    $('#set-is-holiday-text').text(e.model.isWorkday ? '工作日' : '节假日');
                    $('#set-festivals').val(e.model.festivals || '');
                })
                .on('ok', function (okEvent) {
                    var isWorkday = !$('#set-is-holiday').prop('checked'),
                        festivals = $('#set-festivals').val(),
                        dateValue = $$.util.fmt.day(okEvent.model, '-');
                    
                    if (isWorkday != okEvent.model.isWorkday) {
                        // 保存是否工作日
                        _api.setWorkday
                            .one('args', function (e) {
                                e.args = {
                                    value: dateValue,
                                    isWorkday: isWorkday
                                };
                            })
                            .one('success', function (e) {
                                okEvent.model.isWorkday = e.args.isWorkday;
                                okEvent.$button.toggleClass('holiday', !e.args.isWorkday);
                            })();
                    }

                    if (festivals != okEvent.model.festivals) {
                        // 保存节日名称
                        _api.setFestivals
                            .one('args', function (e) {
                                e.args = {
                                    value: dateValue,
                                    festivals: festivals
                                };
                            })
                            .one('success', function (e) {
                                okEvent.model.festivals = e.args.festivals;
                                okEvent.$button.children('.day-name').text(e.args.festivals || (okEvent.model.isToday ? '今天' : ''));
                            })();
                    }

                    // 关闭对话框
                    okEvent.done = true;
                });
        }

        _api.dates();
    });
})(jQuery, pittypat, pittypat.namespace('waln.calendar.management'));
